Resource Design
Resource Naming Conventions
When designing RESTful APIs, the URLs (endpoints) represent resources (things/entities in your system), not actions.
- Resources = nouns → represent objects, collections, or entities.
- Actions = verbs → represent operations (like "getUser", "createOrder").
In REST, we avoid verbs in endpoint paths because the HTTP method (GET, POST, PUT, DELETE) already defines the action.
Why use nouns instead of verbs?
- Consistency → Easy to understand across APIs.
- Clarity → URL describes what the resource is, not what to do with it.
- Flexibility → Operations are handled by HTTP methods instead of encoding them in the URL.
- REST Best Practice → Keeps endpoints clean, predictable, and uniform.
Example of API Naming
Bad (using verbs in path):
/getUsers
/createUser
/deleteUser/123
Problem → Verb in path duplicates what HTTP method already specifies.
Good (using nouns):
GET /users → fetch all users
POST /users → create a new user
GET /users/123 → fetch user with ID 123
PUT /users/123 → update user with ID 123
DELETE /users/123 → delete user with ID 123
Explanation: users is a resource (noun), HTTP method defines the action.
Rules of Thumb for Resource Naming
-
Use nouns (plural form)
/users,/orders,/products- Not
/getUser,/createOrder
-
Use hierarchical structure for relationships
/users/123/orders/77
-
Use lowercase with hyphens (for readability)
/user-profilesnot/UserProfilesor/user_profiles
-
Avoid actions/verbs in URLs
- Don't use
/activateAccount - Instead →
POST /accounts/123/activation
- Don't use
-
Keep it consistent across the API
- Don’t mix plural
/usersand singular/orderin same design.
- Don’t mix plural
When to Use Singular Resource Names?
If the API represents a unique, singular resource, it might make sense to use a singular name. For example, an API for a single user profile might use /profile instead of /profiles.
Request & Response Structure
Request Structure
The request sent by the client typically consists of the following components:
- URL: The endpoint or resource being accessed.
- HTTP Method: The type of action to be performed (
GET,POST,PUT,DELETE). - Headers: Contain metadata about the request (e.g., content type, authentication).
- Body: For methods like
POSTorPUT, the body contains the actual data being sent, typically in JSON format.
Response Structure
The server's response will also be in JSON format, containing the result of the request. The response typically includes:
- Status Code: Indicates the success or failure of the request (e.g.,
200 OK,201 Created,400 Bad Request). - Headers: Provides additional information about the response (e.g., content type, caching).
- Body: Contains the data or message returned by the server.
Path Parameters
Path parameters (also called URL parameters or route parameters) are used to identify specific resources in an API. They are part of the URL path itself and are usually mandatory.
- Mandatory (usually required to access the resource).
- Identify specific resource(s).
- Part of the URL path.
- Usually represented in curly braces
{}in API documentation.
When to use:
- To fetch, update, or delete specific resources.
- When the resource hierarchy is clear:
/users/{userId}/orders/{orderId}.
Query Parameters
Query parameters are used to filter, sort, or paginate resources. They appear after the ? in the URL and are usually optional.
- Optional (often).
- Used for filtering, sorting, pagination, or searching.
- Not part of the resource path; instead, they refine the request.
- Key-value pairs, separated by
&.
Path Parameters vs Query Parameters
| Feature | Path Parameter | Query Parameter |
|---|---|---|
| Purpose | Identify specific resource | Filter, sort, or refine resource |
| Mandatory | Usually yes | Usually optional |
| Part of URL | Yes | No (after ?) |
| Example URL | /users/123 | /users?role=admin&status=active |
| Best use case | Fetch, update, delete single resource | Filter, sort, paginate resource list |
| Impact on caching | Path usually creates new resource URL (cache key) | Same path, different query can be cached separately |
Pagination
Pagination is the process of splitting large sets of data into smaller chunks (pages) so that the client can request and navigate through them efficiently.
There are three common strategies in REST API design:
Limit & Offset Pagination
This is the most common and simplest form of pagination.
- limit → how many items to return per request.
- offset → how many items to skip before starting to return results.
GET /api/v1/products?limit=10&offset=20
limit=10 → return 10 products
offset=20 → skip the first 20 products, start from the 21st
Advantages:
- Easy to implement
- Familiar and intuitive
Disadvantages:
- Inefficient for large offsets (e.g., offset=100000 requires skipping a lot of rows).
- Data inconsistency if records are inserted/deleted between requests.
Page-based Pagination
This is a variant of limit/offset where instead of offset, you use page numbers.
GET /api/v1/products?page=3&limit=10
page=3→ return the 3rd pagelimit=10→ 10 items per page
This internally translates to:
- skip = (page - 1) × limit → (3-1)×10 = 20
- same as offset=20
Advantages:
- User-friendly ("Page 1, Page 2...")
- Simple for UI navigation Disadvantages:
- Suffers from the same large dataset inefficiency as offset
Cursor-based Pagination (a.k.a. Keyset Pagination)
Instead of numeric offsets, this uses a pointer (cursor) to the last item fetched. The cursor is usually a unique, sequential, or sortable field (like id or created_at).
GET /api/v1/products?limit=10&cursor=21
cursor=21→ start after product with ID=21limit=10→ return next 10 items
Advantages:
- Efficient for large datasets
- Consistent results even if new records are inserted/deleted
- Scales well for APIs with continuous scrolling (e.g., Twitter feed)
Disadvantages:
- More complex to implement
- Cursors must be securely encoded (not just raw IDs)
Filtering
Filtering allows clients to narrow down results based on specific fields or conditions.
- Use query parameters for filters.
- Support multiple filters.
- Use consistent naming.
- Consider operators for ranges, dates, etc.
GET /api/v1/products?category=electronics&minPrice=100&maxPrice=1000&brand=sony
Operators (Advanced Filtering):
price[gt]=100→ greater than 100price[lte]=1000→ less than or equal to 1000created_at[between]=2023-01-01,2023-12-31
GET /api/v1/orders?status=completed&price[gte]=100&price[lte]=500
Sorting
Sorting defines the order of returned results.
- Use a
sortquery parameter. - Prefix with
-for descending order. - Allow multiple fields.
GET /api/v1/products?sort=-price,name
- First, sort by price (descending).
- Then, for items with the same price, sort by name (ascending).
Searching
Searching allows clients to perform keyword-based queries across one or multiple fields.
- Use a general
qparameter for free-text search. - Allow field-specific searches if needed.
- For complex cases, integrate with full-text search (Elasticsearch, PostgreSQL
tsvector, etc.).
GET /api/v1/products?name=macbook&brand=apple